#include "WebServer.h"

#include <nlohmann/json.hpp>
#include <iostream>
#include <fstream>
#include <sstream>

using json = nlohmann::json;

using namespace jetcar;

std::mutex camera_mutex; // 全局互斥锁

std::string get_local_ip();
void setup_mjpeg_stream(httplib::Server& svr, UsbCamera& camera);
std::string get_current_time();
// 检查 httplib 版本
// void check_httplib_version() {
//     std::cout << "httplib version: " 
//               << httplib::CPPHTTPLIB_VERSION << std::endl;
// }

// 🔴 修正：在 .cpp 文件中定义 StreamState，避免头文件暴露
// 原子类型用显式初始化，避免拷贝
struct StreamState {
    std::atomic<uint64_t> frame_count;  // 不直接赋值，在构造时初始化
    std::chrono::steady_clock::time_point last_frame_time;
    std::atomic<bool> is_running;

    // 🔴 新增构造函数：显式初始化原子类型（避免拷贝）
    StreamState() : frame_count(0), is_running(true) {}
};


void setup_status_page(httplib::Server& svr, UsbCamera& camera) 
{
    svr.Get("/", [](const httplib::Request& req, httplib::Response& res) {
        std::string html = R"(
<!DOCTYPE html>
<html>
<head>
    <title>视频流监控</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .container { max-width: 800px; margin: 0 auto; }
        .status { background: #f5f5f5; padding: 10px; border-radius: 5px; margin: 10px 0; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🎥 视频流监控</h1>
        <div class="status">
            <p><a href="/video" target="_blank">📹 查看视频流</a></p>
            <p><a href="/status">📊 系统状态</a></p>
        </div>
        <img src="/video" alt="实时视频流" style="max-width: 100%; border: 1px solid #ccc;">
    </div>
</body>
</html>
        )";
        res.set_content(html, "text/html");
    });
    
    svr.Get("/status", [&](const httplib::Request& req, httplib::Response& res) {
        auto status = R"({
            "camera_running": )" + (camera.isRunning() ? std::string("true") : std::string("false")) + R"(,
            "stream_active": true,
            "timestamp": ")" + get_current_time() + R"("
        })";
        res.set_content(status, "application/json");
    });
}

std::string get_current_time() {
    auto now = std::chrono::system_clock::now();
    auto time_t = std::chrono::system_clock::to_time_t(now);
    std::stringstream ss;
    ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
    return ss.str();
}

// 读取前端文件（HTML/CSS/JS）
static std::string readFile(const std::string& path) {
    std::ifstream file(path);
    if (!file.is_open()) {
        throw std::runtime_error("无法读取文件：" + path);
    }
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

void jetcar::startWebServer(
    httplib::Server& svr,
    std::atomic<int>& target_speed,
    std::atomic<int>& current_dir,
    const Config& cfg,
    jetcar::MotorController& motor,
    UsbCamera& camera
) 
{
    svr.set_socket_options([](socket_t sock) {

        // 关键：启用端口复用（允许绑定 TIME_WAIT 状态的端口）
        int reuse = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));

        int flag = 1;
        setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)); // 禁用 Nagle
    });

    // 预加载前端文件（启动时读取一次，提升性能）
    std::string html_content, css_content, js_content;
    try {
        html_content = readFile("./web/index.html");
        css_content = readFile("./web/css/style.css");
        js_content = readFile("./web/js/control.js");
        std::cout << "[Web] 前端文件加载成功" << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "[Web] 前端文件加载失败：" << e.what() << std::endl;
        return;
    }

    // 1. 路由：首页（返回 HTML，自动注入IP）
    svr.Get("/", [&](const httplib::Request&, httplib::Response& res) {
        // 1. 获取自身IP和服务端口
        std::string local_ip = get_local_ip();
        std::string web_port = std::to_string(cfg.web_port); // 自动读取配置的端口（如8081）

        // 2. 替换HTML中摄像头地址：src="/camera" → 带IP+端口+防缓存参数
        std::string updated_html = html_content; // 基于你原有html_content变量

        // 关键修改：target 匹配 HTML 中原 src 的完整值（注意双引号和 base64 字符串完全一致）
        std::string target = "src=\"\"";
        
        // replacement 是完整的流地址（带防缓存），去掉多余拼接
        std::string replacement = "src='http://" + local_ip + ":" + web_port + "/camera?rand='+Math.random() onload='document.getElementById(\"camera-status\").textContent=\"加载成功\"'";

        //std::cout << "******************"<<std::endl;
        //exit(0);
        // 执行替换（替换原 base64 src 为流地址）
        size_t pos = 0;
        while ((pos = updated_html.find(target, pos)) != std::string::npos) {
            updated_html.replace(pos, target.length(), replacement);
            pos += replacement.length();
        }

        // 3. 返回修改后的HTML
        res.set_content(updated_html, "text/html; charset=utf-8");
    });

    // 2. 路由：CSS 样式
    svr.Get("/css/style.css", [&](const httplib::Request&, httplib::Response& res) {
        res.set_content(css_content, "text/css; charset=utf-8");
    });

    // 3. 路由：JS 交互逻辑
    svr.Get("/js/control.js", [&](const httplib::Request&, httplib::Response& res) {
        res.set_content(js_content, "application/javascript; charset=utf-8");
    });

    // 4. 路由：方向控制接口（POST）
    svr.Post("/ctrl", [&](const httplib::Request& req, httplib::Response& res) {
        try {
            auto j = json::parse(req.body);
            int dir_code = j.value("d", 0);
            DirectionCode new_dir 
                = static_cast<DirectionCode>(dir_code);
          

            // 更新方向并控制电机
            current_dir = dir_code;
            int speed = target_speed.load();
           
            // 调用电机 setTarget 时，转换为 MotorController::Direction
            motor.setTarget(
                static_cast<DirectionCode>(new_dir),
                speed
            );

            // 计算轮速
            int left_speed = 0, right_speed = 0;
            DirectionLogic::calculateWheelSpeeds(new_dir, speed, left_speed, right_speed);

            // 返回响应
            json resp = {
                {"ok", true},
                {"direction", dir_code},
                {"direction_name", DirectionLogic::getDirectionName(new_dir)},
                {"target_speed", speed},
                {"left_wheel_speed", left_speed},
                {"right_wheel_speed", right_speed},
                {"detailed_direction", DirectionLogic::getDetailedDirection(new_dir, left_speed, right_speed)}
            };
            res.set_content(resp.dump(), "application/json");
        } catch (const std::exception& e) {
            json resp = {{"ok", false}, {"error", e.what()}, {"direction", -1}};
            res.status = 400;
            res.set_content(resp.dump(), "application/json");
        }
    });

    // 5. 路由：速度调节接口（POST）
    svr.Post("/speed", [&](const httplib::Request& req, httplib::Response& res) {
        try {
            auto j = json::parse(req.body);
            int s = j.value("s", cfg.default_speed);
            // 速度限制
            s = std::max(cfg.min_speed, std::min(s, cfg.max_speed));
            target_speed = s;

            // 同步更新电机速度
            int dir = current_dir.load();
            DirectionCode dirCode = static_cast<DirectionCode>(dir);
            motor.setTarget(dir, s);
            // 计算轮速
            int left_speed = 0, right_speed = 0;
            DirectionLogic::calculateWheelSpeeds(dirCode, s, left_speed, right_speed);

            // 返回响应
            json resp = {
                {"ok", true},
                {"target_speed", s},
                {"min_speed", cfg.min_speed},
                {"max_speed", cfg.max_speed},
                {"left_wheel_speed", left_speed},
                {"right_wheel_speed", right_speed}
            };
            res.set_content(resp.dump(), "application/json");
        } catch (const std::exception& e) {
            json resp = {{"ok", false}, {"error", e.what()}, {"target_speed", -1}};
            res.status = 400;
            res.set_content(resp.dump(), "application/json");
        }
    });

    // 6. 路由：状态查询接口（GET）
    svr.Get("/status", [&](const httplib::Request&, httplib::Response& res) {
        DirectionCode dir = static_cast<DirectionCode>(current_dir.load());
        int speed = target_speed.load();
        int left_speed = 0, right_speed = 0;
        DirectionLogic::calculateWheelSpeeds(dir, speed, left_speed, right_speed);

        json resp = {
            {"ok", true},
            {"direction", static_cast<int>(dir)},
            {"direction_name", DirectionLogic::getDirectionName(dir)},
            {"target_speed", speed},
            {"left_wheel_speed", left_speed},
            {"right_wheel_speed", right_speed},
            {"detailed_direction", DirectionLogic::getDetailedDirection(dir, left_speed, right_speed)},
            {"camera_running", camera.isRunning()}
        };
        res.set_content(resp.dump(), "application/json");
    });

    // 7. 摄像头流接口（httplib 0.27.0 最终兼容版）
    //setup_mjpeg_stream(svr, camera);
// 🔴 新增路由：返回单帧摄像头图片（用于前端轮询）
    svr.Get("/camera_single", [&](const httplib::Request&, httplib::Response& res) {
        if (!camera.isRunning()) {
            res.status = 503;
            res.set_content("摄像头未启动", "text/plain");
            return;
        }

        std::lock_guard<std::mutex> lock(camera_mutex); // 加锁，确保采集过程独占
        std::vector<unsigned char> mjpeg_frame;
        if (!camera.getFrame(mjpeg_frame) || mjpeg_frame.empty()) {
            res.status = 404;
            res.set_content("未获取到图像", "text/plain");
            return;
        }

        res.status = 200;
        res.set_header("Cache-Control", "no-cache, no-store, must-revalidate");
        res.set_header("Pragma", "no-cache");
        res.set_header("Expires", "0");

        // 🔴 方案一正确写法：三参数，强转 size_t + 显式 content_type
        res.set_content(
            reinterpret_cast<const char*>(mjpeg_frame.data()),
            static_cast<size_t>(mjpeg_frame.size()),  // 强转长度
            "image/jpeg"                               // 补充 content_type
        );
    });

    // 启动 Web 服务
    std::cout << "[Web] 服务启动成功，访问地址：http://" << "0.0.0.0" << ":" << cfg.web_port << std::endl;
    std::cout << "[Web] 操作说明：按住方向按钮执行，松开/移开自动停止（支持移动端）" << std::endl;
    auto ret = svr.listen("0.0.0.0", cfg.web_port);
    if (!ret) {
        // 输出失败信息（包含端口，方便定位）
        std::cerr << "[WebServer] 启动失败！无法绑定端口 " << cfg.web_port 
              << "（可能原因：端口被占用、权限不足、地址错误）" << std::endl;
        exit (-1); 
    }
    
}


#if 0

void setup_mjpeg_stream(httplib::Server& svr, UsbCamera& camera) {
    svr.Get("/camera", [&](const httplib::Request&, httplib::Response& res) {
        if (!camera.isRunning()) {
            res.status = 503;
            res.set_content("摄像头未启动", "text/plain");
            return;
        }

        // 1. 仅设置必要响应头（httplib 自动处理 HTTP 头，无需手动拼接）
        res.status = 200;
        res.set_header("Access-Control-Allow-Origin", "*");
        res.set_content_provider(
            "multipart/x-mixed-replace; boundary=jetcar_frame",
            [&](httplib::DataSink& sink) {
                // 2. 原子变量控制线程退出（避免野指针）
                std::atomic<bool> is_running = true;

                // 3. 启动独立推流线程（核心：绕开 httplib 回调调度）
                std::thread stream_thread([&, &sink, &is_running]() {
                    std::vector<unsigned char> mjpeg_frame;
                    uint64_t frame_count = 0;
                    auto last_frame_time = std::chrono::steady_clock::now();

                    // 推流循环（独立线程，无 httplib 干扰）
                    while (is_running && camera.isRunning()) {
                        // 4. 帧率控制（10fps，Jetson 无压力）
                        auto now = std::chrono::steady_clock::now();
                        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_frame_time);
                        if (elapsed < std::chrono::milliseconds(100)) {
                            std::this_thread::sleep_for(std::chrono::milliseconds(5));
                            continue;
                        }

                        // 5. 获取有效帧（跳过空帧/错误帧）
                        if (!camera.getFrame(mjpeg_frame) || mjpeg_frame.empty()) {
                            std::this_thread::sleep_for(std::chrono::milliseconds(50));
                            continue;
                        }

                        try {
                            // 6. 拼接极简分块（仅保留必要字段，减少开销）
                            std::string frame_data = "--jetcar_frame\r\n";
                            frame_data += "Content-Type: image/jpeg\r\n";
                            frame_data += "Content-Length: " + std::to_string(mjpeg_frame.size()) + "\r\n\r\n";
                            frame_data.append(reinterpret_cast<const char*>(mjpeg_frame.data()), mjpeg_frame.size());
                            frame_data += "\r\n\r\n";  // 双空行确保浏览器解析

                            // 7. 写入数据（检查客户端是否断开）
                            if (!sink.write(frame_data.data(), frame_data.size())) {
                                std::cout << "[MJPEG] 客户端断开连接" << std::endl;
                                break;
                            }

                            // 8. 更新状态+日志
                            frame_count++;
                            last_frame_time = now;
                            // if (frame_count % 20 == 0) {
                            //     std::cout << "[MJPEG] 已发送 " << frame_count << " 帧，大小：" << mjpeg_frame.size() << " 字节" << std::endl;
                            // }
                        } catch (const std::exception& e) {
                            std::cerr << "[MJPEG] 帧发送异常：" << e.what() << std::endl;
                            break;
                        }
                    }

                    // 9. 清理资源
                    is_running = false;
                    sink.done();
                    std::cout << "[MJPEG] 流结束，共发送 " << frame_count << " 帧" << std::endl;
                });

                // 10. 回调结束时停止线程（避免内存泄漏）
                return [&is_running, &stream_thread]() {
                    is_running = false;
                    if (stream_thread.joinable()) {
                        stream_thread.join();
                    }
                };
            }
        );
    });
}


#endif

// 读取设备第一个非回环网卡的局域网IP（自动获取）
std::string get_local_ip() {
    std::string local_ip = "127.0.0.1"; // 默认本地回环
    struct ifaddrs *ifap, *ifa;
    struct sockaddr_in *sa;
    char *addr;

    if (getifaddrs(&ifap) == -1) {
        perror("getifaddrs");
        return local_ip;
    }

    for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == nullptr) continue;
        if (ifa->ifa_addr->sa_family != AF_INET) continue; // 只取IPv4
        if (strcmp(ifa->ifa_name, "lo") == 0) continue; // 跳过回环网卡

        sa = (struct sockaddr_in *)ifa->ifa_addr;
        addr = inet_ntoa(sa->sin_addr);
        local_ip = addr;
        break; // 取第一个有效网卡IP（可根据需要调整）
    }

    freeifaddrs(ifap);
    return local_ip;
}



